package com.sky.service.impl;

import com.sky.dto.GoodsSalesDTO;
import com.sky.entity.Orders;
import com.sky.mapper.EmployeeMapper;
import com.sky.mapper.OrderMapper;
import com.sky.service.ReportService;
import com.sky.service.WorkspaceService;
import com.sky.vo.*;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.servlet.http.HttpServletResponse;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 营业额统计
 */
@Service
public class ReportServiceImpl implements ReportService {
  
  @Autowired
  private OrderMapper orderMapper;
  @Autowired
  private EmployeeMapper employeeMapper;
  @Autowired
  private WorkspaceService workspaceService;
  
  /**
   * 营业额统计
   * @param begin
   * @param end
   */
  @Override
  public TurnoverReportVO turnoverStatistics(LocalDate begin, LocalDate end) {
    // 存储开始到结束的所有时间
    List<LocalDate> dateList = new ArrayList<>();
    
    // 补全开始到结束的所有时间
    dateList.add(begin);
    while(begin.isBefore(end)) {
      begin = begin.plusDays(1);
      dateList.add(begin);
    }
    // 日期转字符串 逗号分割 两个方式 2022-10-01,2022-10-02,2022-10-03
    // StringUtils.join(dateList, ',')
    // String dateListStr = dateList.stream().map(LocalDate::toString).collect(Collectors.joining(","));
    
    
    // 计算每天的营业额
    List<BigDecimal> totalTurnovers = new ArrayList<>();
    for (LocalDate date : dateList) {
      BigDecimal total_turnover = orderMapper.calculateTurnoverForDate(date, Orders.COMPLETED);
      totalTurnovers.add(total_turnover);
    }
    
    // 构建返回的数据
    TurnoverReportVO reportVO = TurnoverReportVO.builder()
            .dateList(StringUtils.join(dateList, ','))
                .turnoverList(StringUtils.join(totalTurnovers, ','))
                    .build();
    return reportVO;
  }
  
  /**
   * 用户统计
   * @param begin
   * @param end
   */
  @Override
  public UserReportVO userStatistics(LocalDate begin, LocalDate end) {
    // 存储开始到结束的所有时间
    List<LocalDate> dateList = new ArrayList<>();
    
    // 补全开始到结束的所有时间
    dateList.add(begin);
    while(begin.isBefore(end)) {
      begin = begin.plusDays(1);
      dateList.add(begin);
    }
    
    // 用户新增量和总量
    List<Integer> newUserCountList = new ArrayList<>();
    List<Integer> totalUserCountList = new ArrayList<>();
    
    for (LocalDate date : dateList) {
      Integer newUserCount = employeeMapper.getNewUserCountByDate(date);
      newUserCountList.add(newUserCount);
      Integer totalUserCount = employeeMapper.getTotalUserCountByDate(date);
      totalUserCountList.add(totalUserCount);
    }
    
    return UserReportVO.builder()
        .newUserList(StringUtils.join(newUserCountList, ','))
        .totalUserList(StringUtils.join(totalUserCountList, ','))
        .dateList(StringUtils.join(dateList, ','))
        .build();
  }
  
  /**
   * 订单统计
   * @param begin
   * @param end
   */
  @Override
  public OrderReportVO orderStatistics(LocalDate begin, LocalDate end) {
    // 1.补全日期 装进集合中
    List<LocalDate> dateList = new ArrayList<>();
    dateList.add(begin);
    while (begin.isBefore(end)) {
      begin = begin.plusDays(1);
      dateList.add(begin);
    }
    
    // 2.存放每天 订单数 和 有效订单数
    List<Integer> totalOrderCountList = new ArrayList<>();
    List<Integer> validOrderCountList = new ArrayList<>();
    for (LocalDate date : dateList) {
      LocalDateTime beginTime = LocalDateTime.of(date, LocalTime.MIN);
      LocalDateTime endTime = LocalDateTime.of(date, LocalTime.MAX);
      
      // 获取当天全部订单数
      Integer totalOrderCount = getOrderCount(beginTime, endTime, null);
      totalOrderCountList.add(totalOrderCount);
      // 获取当天有效订单数
      Integer validOrderCount = getOrderCount(beginTime, endTime, Orders.COMPLETED);
      validOrderCountList.add(validOrderCount);
    }
    
    // 3.计算时间区间的 全部订单数 和 有效订单数
    Integer totalOrderCount = totalOrderCountList.stream().reduce(Integer::sum).get();
    Integer validOrderCount = validOrderCountList.stream().reduce(Integer::sum).get();
    
    // 4.计算订单完成率
    double completionRate = 0.0;
    if (totalOrderCount != null && totalOrderCount > 0) {
      completionRate = (validOrderCount.doubleValue() / totalOrderCount.doubleValue());
    }
    
    return OrderReportVO.builder()
        .dateList(StringUtils.join(dateList, ","))
        .orderCountList(StringUtils.join(totalOrderCountList, ','))
        .validOrderCountList(StringUtils.join(validOrderCountList, ','))
        .totalOrderCount(totalOrderCount)
        .validOrderCount(validOrderCount)
        .orderCompletionRate(completionRate)
        .build();
  }
  
  /**
   * 获取指定时间段内特定状态的订单数量。
   * @param beginTime 开始时间
   * @param endTime 结束时间
   * @param status 订单状态
   */
  private Integer getOrderCount(LocalDateTime beginTime, LocalDateTime endTime, Integer status) {
    Map<String, Object> map = new HashMap<>();
    map.put("begin", beginTime);
    map.put("end", endTime);
    map.put("status", status);
    return orderMapper.getOrderCount(map);
  }
  
  /**
   * 销量top10
   * @return
   */
  @Override
  public SalesTop10ReportVO SalesTop10ReportVO(LocalDate begin, LocalDate end) {
    LocalDateTime beginTime = LocalDateTime.of(begin, LocalTime.MIN);
    LocalDateTime endTime = LocalDateTime.of(end, LocalTime.MAX);
    List<GoodsSalesDTO> salesTop10List = orderMapper.getSalesTop10(beginTime, endTime);
    
    // name 和 number 单独抽取到集合 的两种方式
    List<String> nameList = new ArrayList<>();
    for (GoodsSalesDTO goodsSalesDTO : salesTop10List) {
      nameList.add(goodsSalesDTO.getName());
    }
    List<Integer> numberList = salesTop10List.stream().map(GoodsSalesDTO::getNumber).collect(Collectors.toList());
    
    // 封装返回结果数据
    return SalesTop10ReportVO.builder()
        .nameList(StringUtils.join(nameList, ','))
        .numberList(StringUtils.join(numberList, ','))
        .build();
  }
  
  /**
   * 导出运营数据报表
   */
  @Override
  public void exportBusinessData(HttpServletResponse response) throws Exception {
    // 1.查数据库，获取营业数据 --- 最近30天数据
    LocalDate begin = LocalDate.now().minusDays(30);
    LocalDate end = LocalDate.now().minusDays(1);
    BusinessDataVO businessData = workspaceService.getBusinessData(
        LocalDateTime.of(begin, LocalTime.MIN), LocalDateTime.of(end, LocalTime.MAX)
    );
    
    // 2.通过poi将数据写入到excel
    InputStream in = getClass().getClassLoader().getResourceAsStream("template/运营数据报表模板.xlsx");
    // FileInputStream in = new FileInputStream("/Users/ilysusu/Desktop/sky-take-out/sky-server/src/main/resources/template/运营数据报表模板.xlsx");
    XSSFWorkbook excel = new XSSFWorkbook(in); // 基于模板创建excel文件
    XSSFSheet sheet = excel.getSheetAt(0); // 读取文件中第一页  或者 excel.getSheet("Sheet1")
    
    // 在对应行 对应行单元格 写入数据
    sheet.getRow(1).getCell(1).setCellValue("时间："+ begin +" - "+end);
    sheet.getRow(3).getCell(2).setCellValue(businessData.getTurnover());
    sheet.getRow(3).getCell(4).setCellValue(businessData.getOrderCompletionRate());
    sheet.getRow(3).getCell(6).setCellValue(businessData.getNewUsers());
    sheet.getRow(4).getCell(2).setCellValue(businessData.getValidOrderCount());
    sheet.getRow(4).getCell(4).setCellValue(businessData.getUnitPrice());
    
    // 填充近30天明细数据
    for (int i = 0; i < 30; i++) {
      LocalDate date = begin.plusDays(i);
      // 查询某一天的营业数据
      BusinessDataVO businessDataOfDay = workspaceService.getBusinessData(LocalDateTime.of(date, LocalTime.MIN), LocalDateTime.of(date, LocalTime.MAX));
      // 获取某一行
      XSSFRow row = sheet.getRow(7 + i);
      // 设置某一行对应单元格 数据
      row.getCell(1).setCellValue(date.toString());
      row.getCell(2).setCellValue(businessDataOfDay.getTurnover());
      row.getCell(3).setCellValue(businessDataOfDay.getValidOrderCount());
      row.getCell(4).setCellValue(businessDataOfDay.getOrderCompletionRate());
      row.getCell(5).setCellValue(businessDataOfDay.getUnitPrice());
      row.getCell(6).setCellValue(businessDataOfDay.getNewUsers());
    }
    
    // 3.通过输出流将excel文件下载到客户端浏览器
    response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
    response.setCharacterEncoding("utf-8");
    response.setHeader("Content-Disposition", "attachment;filename=运营数据报表.xlsx");
    try (OutputStream out = response.getOutputStream()) {
      excel.write(out);
    } finally {
      in.close();
      excel.close();
    }
    
    
  }
}
